﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace LostProjects.Mobile
{
	public partial class TextEditor : Form
	{
		public TextEditor()
		{
			InitializeComponent();

			font_ = this.Font;
		}

		internal string[] Arguments { get; set; }

		private void TextEditor_Load(object sender, EventArgs e)
		{
			if ((Arguments == null) || (Arguments.Length == 0))
			{
			} else
				foreach (var file in Arguments)
					Open(file);
		}

		private void Open(string file)
		{
			Open(file, null);
		}

		Dictionary<string, TextBox> files_ = new Dictionary<string, TextBox>();
		Font font_;
		Color foreColor_ = SystemColors.ControlText, backColor_ = SystemColors.Window;
		bool wordWrap_ = true;

		private string ReadFile(string file, Encoding encoding)
		{
			using (var streamReader = new StreamReader(file, encoding ?? Encoding.Default, true))
				return streamReader.ReadToEnd();
		}

		private void Open(string file, Encoding encoding)
		{
			if (files_.ContainsKey(file))
			{
				switch (MessageBox.Show("File is already opened. Show it for you?", "A copy of file is opened", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1))
				{
				case DialogResult.Yes:
					menuWindow_Click(files_[file].Tag, EventArgs.Empty);
					return;
				case DialogResult.Cancel:
					return;
				case DialogResult.No:
					Create(ReadFile(file, encoding));
					return;
				default:
					throw new InvalidProgramException();
				}
			}

			var textBox = CreateEditor();
			textBox.Text = ReadFile(file, encoding);
			this.Controls.Add(textBox);
			textBox.Name = file;

			files_.Add(file, textBox);

			var menuItem = new MenuItem {
				Text = Path.GetFileNameWithoutExtension(textBox.Name),
			};
			textBox.Tag = menuItem;
			menuItem.Click += new EventHandler(menuWindow_Click);
			menuWindows.MenuItems.Add(menuItem);

			menuWindow_Click(menuItem, EventArgs.Empty);
		}

		void menuWindow_Click(object sender, EventArgs e)
		{
			var menu = sender as MenuItem;
			menu.Checked = true;
			var textBox = files_.Values.Single(editor => editor.Tag == sender);
			textBox.BringToFront();
			this.Text = Path.GetFileNameWithoutExtension(textBox.Name);
			menuWindows.Enabled = true;
			menuSaveAs.Enabled = true;
			menuClose.Enabled = true;
			menuSave.Enabled = true;
			foreach (MenuItem window in menuWindows.MenuItems)
				window.Checked = window == menu;
		}

		private TextBox CreateEditor()
		{
			var editor = new TextBox {
				#region Constant properties
				AcceptsReturn = true,
				AcceptsTab = true,
				Dock = DockStyle.Fill,
				HideSelection = false,
				MaxLength = int.MaxValue,
				Multiline = true,
				ScrollBars = ScrollBars.Both,
				#endregion Constant properties

				#region Configurable properties
				BackColor = backColor_,
				Font = font_,
				ForeColor = foreColor_,
				WordWrap = wordWrap_,
				#endregion Configurable properties
			};

			editor.TextChanged += new EventHandler(editor_TextChanged);

			return editor;
		}

		void editor_TextChanged(object sender, EventArgs e)
		{
			var editor = sender as TextBox;
			var menuItem = editor.Tag as MenuItem;
			if (editor.Modified && !menuItem.Text.StartsWith("*"))
			{
				menuItem.Text = "*" + menuItem.Text;
				this.Text = menuItem.Text;
			}

			if (!editor.Modified && menuItem.Text.StartsWith("*"))
			{
				menuItem.Text.TrimStart('*');
				this.Text = menuItem.Text;
			}
		}

		private void Create(string file)
		{
			var name = Guid.NewGuid().ToString();

			var textBox = CreateEditor();
			textBox.Text = file;
			this.Controls.Add(textBox);

			textBox.Name = name;
			files_.Add(name, textBox);

			var menuItem = new MenuItem {
				Text = Path.GetFileNameWithoutExtension(textBox.Name),
			};
			textBox.Tag = menuItem;
			menuItem.Click += new EventHandler(menuWindow_Click);
			menuWindows.MenuItems.Add(menuItem);

			menuWindow_Click(menuItem, EventArgs.Empty);
		}

		private void menuOpen_Click(object sender, EventArgs e)
		{
			if (openFileDialog.ShowDialog() != DialogResult.OK) return;

			Open(openFileDialog.FileName);
		}

		private MenuItem MenuItem
		{
			get
			{
				return menuWindows.MenuItems.OfType<MenuItem>().Single(item => item.Checked);
			}
		}

		private KeyValuePair<string, TextBox> Current
		{
			get
			{
				return files_.Single(item => item.Value.Tag == MenuItem);
			}
		}

		private void menuClose_Click(object sender, EventArgs e)
		{
			var textBox = Current.Value;
			if (textBox.Modified)
			{
				switch (MessageBox.Show("Text was modified, save it?", textBox.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1))
				{
				case DialogResult.No:
					break;
				case DialogResult.Yes:
					if (!Save()) return;
					break;
				case DialogResult.Cancel:
					return;
				default:
					throw new InvalidProgramException();
				}
			}

			MenuItem.Dispose();
			textBox.Dispose();
			files_.Remove(Current.Key);
			menuWindows.MenuItems.Remove(MenuItem);
			if (menuWindows.MenuItems.Count > 0)
			{
				menuWindow_Click(menuWindows.MenuItems.OfType<MenuItem>().First(), EventArgs.Empty);
			} else
			{
				menuSave.Enabled = false;
				menuSaveAs.Enabled = false;
				menuWindows.Enabled = false;
				menuClose.Enabled = false;
				this.Text = "Text Editor";
			}
		}

		public bool IsNew
		{
			get
			{
				var textBox = Current.Value;
				return Path.GetFullPath(textBox.Name) != textBox.Name;
			}
		}

		private bool Save(bool forceSaveAs)
		{
			var textBox = Current.Value;
			saveFileDialog.FileName = textBox.Name;

			if (forceSaveAs || (IsNew && textBox.Modified))
				if (saveFileDialog.ShowDialog() != DialogResult.OK) return false;

			
			// file is open in another window
			if (files_.ContainsKey(saveFileDialog.FileName) &&
				files_[saveFileDialog.FileName] != textBox)
			{
				throw new NotImplementedException("Saving to an open file");
			}

			var menuItem = MenuItem;
			files_.Remove(textBox.Name);
			textBox.Name = saveFileDialog.FileName;
			files_.Add(textBox.Name, textBox);

			using (var streamWriter = new StreamWriter(textBox.Name))
				streamWriter.Write(textBox.Text);

			textBox.Modified = false;
			menuItem.Text = Path.GetFileNameWithoutExtension(textBox.Name);
			this.Text = menuItem.Text;

			return true;
		}

		private bool Save()
		{
			return Save(false);
		}

		private void menuSaveAs_Click(object sender, EventArgs e)
		{
			Save(true);
		}

		private void menuSave_Click(object sender, EventArgs e)
		{
			Save();
		}
	}
}